// 前端防刷监控工具

/**
 * 防刷监控器
 */
class AntiCheatMonitor {
  constructor() {
    this.behaviorData = {
      clickTimes: [],
      mouseMoves: [],
      keystrokes: [],
      scrollEvents: [],
      focusEvents: []
    }
    
    this.isMonitoring = false
    this.sessionId = this.generateSessionId()
    
    this.init()
  }
  
  /**
   * 初始化监控
   */
  init() {
    // #ifdef H5
    if (typeof window !== 'undefined') {
      this.initBrowserMonitoring()
    }
    // #endif
  }
  
  /**
   * 初始化浏览器监控
   */
  initBrowserMonitoring() {
    // #ifdef H5
    // 监控鼠标移动
    document.addEventListener('mousemove', this.handleMouseMove.bind(this), { passive: true })
    
    // 监控点击事件
    document.addEventListener('click', this.handleClick.bind(this), { passive: true })
    
    // 监控键盘事件
    document.addEventListener('keydown', this.handleKeydown.bind(this), { passive: true })
    
    // 监控滚动事件
    document.addEventListener('scroll', this.handleScroll.bind(this), { passive: true })
    
    // 监控焦点事件
    window.addEventListener('focus', this.handleFocus.bind(this), { passive: true })
    window.addEventListener('blur', this.handleBlur.bind(this), { passive: true })
    
    // 监控页面可见性变化
    document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this), { passive: true })
    // #endif
  }
  
  /**
   * 开始监控
   */
  startMonitoring() {
    this.isMonitoring = true
    this.behaviorData = {
      clickTimes: [],
      mouseMoves: [],
      keystrokes: [],
      scrollEvents: [],
      focusEvents: []
    }
  }
  
  /**
   * 停止监控
   */
  stopMonitoring() {
    this.isMonitoring = false
  }
  
  /**
   * 处理鼠标移动
   */
  handleMouseMove(event) {
    if (!this.isMonitoring) return
    
    const now = Date.now()
    this.behaviorData.mouseMoves.push({
      x: event.clientX,
      y: event.clientY,
      timestamp: now
    })
    
    // 只保留最近100个移动事件
    if (this.behaviorData.mouseMoves.length > 100) {
      this.behaviorData.mouseMoves.shift()
    }
  }
  
  /**
   * 处理点击事件
   */
  handleClick(event) {
    if (!this.isMonitoring) return
    
    const now = Date.now()
    this.behaviorData.clickTimes.push({
      x: event.clientX,
      y: event.clientY,
      target: event.target.tagName,
      timestamp: now
    })
    
    // 只保留最近50个点击事件
    if (this.behaviorData.clickTimes.length > 50) {
      this.behaviorData.clickTimes.shift()
    }
  }
  
  /**
   * 处理键盘事件
   */
  handleKeydown(event) {
    if (!this.isMonitoring) return
    
    const now = Date.now()
    this.behaviorData.keystrokes.push({
      key: event.key,
      code: event.code,
      timestamp: now
    })
    
    // 只保留最近50个按键事件
    if (this.behaviorData.keystrokes.length > 50) {
      this.behaviorData.keystrokes.shift()
    }
  }
  
  /**
   * 处理滚动事件
   */
  handleScroll(event) {
    if (!this.isMonitoring) return
    
    const now = Date.now()
    this.behaviorData.scrollEvents.push({
      scrollY: window.scrollY,
      timestamp: now
    })
    
    // 只保留最近30个滚动事件
    if (this.behaviorData.scrollEvents.length > 30) {
      this.behaviorData.scrollEvents.shift()
    }
  }
  
  /**
   * 处理焦点事件
   */
  handleFocus() {
    if (!this.isMonitoring) return
    
    this.behaviorData.focusEvents.push({
      type: 'focus',
      timestamp: Date.now()
    })
  }
  
  /**
   * 处理失焦事件
   */
  handleBlur() {
    if (!this.isMonitoring) return
    
    this.behaviorData.focusEvents.push({
      type: 'blur',
      timestamp: Date.now()
    })
  }
  
  /**
   * 处理页面可见性变化
   */
  handleVisibilityChange() {
    if (!this.isMonitoring) return
    
    this.behaviorData.focusEvents.push({
      type: document.hidden ? 'hidden' : 'visible',
      timestamp: Date.now()
    })
  }
  
  /**
   * 分析用户行为
   * @returns {Object} 行为分析结果
   */
  analyzeBehavior() {
    const analysis = {
      sessionId: this.sessionId,
      timestamp: Date.now(),
      riskScore: 0,
      riskFactors: [],
      behaviorMetrics: this.calculateBehaviorMetrics()
    }
    
    // 分析点击模式
    const clickAnalysis = this.analyzeClickPattern()
    if (clickAnalysis.suspicious) {
      analysis.riskScore += clickAnalysis.riskScore
      analysis.riskFactors.push(clickAnalysis.reason)
    }
    
    // 分析鼠标移动模式
    const mouseAnalysis = this.analyzeMouseMovement()
    if (mouseAnalysis.suspicious) {
      analysis.riskScore += mouseAnalysis.riskScore
      analysis.riskFactors.push(mouseAnalysis.reason)
    }
    
    // 分析键盘输入模式
    const keyboardAnalysis = this.analyzeKeyboardPattern()
    if (keyboardAnalysis.suspicious) {
      analysis.riskScore += keyboardAnalysis.riskScore
      analysis.riskFactors.push(keyboardAnalysis.reason)
    }
    
    // 分析页面交互模式
    const interactionAnalysis = this.analyzeInteractionPattern()
    if (interactionAnalysis.suspicious) {
      analysis.riskScore += interactionAnalysis.riskScore
      analysis.riskFactors.push(interactionAnalysis.reason)
    }
    
    return analysis
  }
  
  /**
   * 分析点击模式
   */
  analyzeClickPattern() {
    const clicks = this.behaviorData.clickTimes
    
    if (clicks.length < 3) {
      return { suspicious: false }
    }
    
    // 计算点击间隔
    const intervals = []
    for (let i = 1; i < clicks.length; i++) {
      intervals.push(clicks[i].timestamp - clicks[i-1].timestamp)
    }
    
    // 计算间隔的标准差
    const avgInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length
    const variance = intervals.reduce((sum, interval) => sum + Math.pow(interval - avgInterval, 2), 0) / intervals.length
    const stdDev = Math.sqrt(variance)
    
    // 如果点击间隔过于规律，可能是机器行为
    if (stdDev < 50 && avgInterval < 1000) {
      return {
        suspicious: true,
        riskScore: 30,
        reason: '点击模式过于规律'
      }
    }
    
    // 检查点击位置是否过于集中
    const positions = clicks.map(click => ({ x: click.x, y: click.y }))
    const positionVariance = this.calculatePositionVariance(positions)
    
    if (positionVariance < 100) {
      return {
        suspicious: true,
        riskScore: 25,
        reason: '点击位置过于集中'
      }
    }
    
    return { suspicious: false }
  }
  
  /**
   * 分析鼠标移动模式
   */
  analyzeMouseMovement() {
    const moves = this.behaviorData.mouseMoves
    
    if (moves.length < 10) {
      return { suspicious: false }
    }
    
    // 检查是否有鼠标移动（机器人可能没有鼠标移动）
    const totalDistance = this.calculateTotalMouseDistance(moves)
    
    if (totalDistance < 100) {
      return {
        suspicious: true,
        riskScore: 40,
        reason: '缺少自然的鼠标移动'
      }
    }
    
    // 检查移动轨迹是否过于直线
    const straightLineRatio = this.calculateStraightLineRatio(moves)
    
    if (straightLineRatio > 0.9) {
      return {
        suspicious: true,
        riskScore: 35,
        reason: '鼠标移动轨迹过于直线'
      }
    }
    
    return { suspicious: false }
  }
  
  /**
   * 分析键盘输入模式
   */
  analyzeKeyboardPattern() {
    const keystrokes = this.behaviorData.keystrokes
    
    if (keystrokes.length < 5) {
      return { suspicious: false }
    }
    
    // 计算按键间隔
    const intervals = []
    for (let i = 1; i < keystrokes.length; i++) {
      intervals.push(keystrokes[i].timestamp - keystrokes[i-1].timestamp)
    }
    
    const avgInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length
    const variance = intervals.reduce((sum, interval) => sum + Math.pow(interval - avgInterval, 2), 0) / intervals.length
    const stdDev = Math.sqrt(variance)
    
    // 如果按键间隔过于规律，可能是机器输入
    if (stdDev < 20 && avgInterval < 200) {
      return {
        suspicious: true,
        riskScore: 30,
        reason: '键盘输入模式过于规律'
      }
    }
    
    return { suspicious: false }
  }
  
  /**
   * 分析页面交互模式
   */
  analyzeInteractionPattern() {
    const focusEvents = this.behaviorData.focusEvents
    
    // 检查是否有页面切换行为
    const hasPageSwitching = focusEvents.some(event => event.type === 'blur' || event.type === 'hidden')
    
    if (!hasPageSwitching && focusEvents.length > 0) {
      return {
        suspicious: true,
        riskScore: 20,
        reason: '缺少正常的页面切换行为'
      }
    }
    
    return { suspicious: false }
  }
  
  /**
   * 计算行为指标
   */
  calculateBehaviorMetrics() {
    return {
      clickCount: this.behaviorData.clickTimes.length,
      mouseMoveCount: this.behaviorData.mouseMoves.length,
      keystrokeCount: this.behaviorData.keystrokes.length,
      scrollCount: this.behaviorData.scrollEvents.length,
      focusEventCount: this.behaviorData.focusEvents.length,
      totalMouseDistance: this.calculateTotalMouseDistance(this.behaviorData.mouseMoves),
      averageClickInterval: this.calculateAverageClickInterval(),
      sessionDuration: Date.now() - (this.behaviorData.clickTimes[0]?.timestamp || Date.now())
    }
  }
  
  /**
   * 计算位置方差
   */
  calculatePositionVariance(positions) {
    if (positions.length < 2) return 0
    
    const avgX = positions.reduce((sum, pos) => sum + pos.x, 0) / positions.length
    const avgY = positions.reduce((sum, pos) => sum + pos.y, 0) / positions.length
    
    const varianceX = positions.reduce((sum, pos) => sum + Math.pow(pos.x - avgX, 2), 0) / positions.length
    const varianceY = positions.reduce((sum, pos) => sum + Math.pow(pos.y - avgY, 2), 0) / positions.length
    
    return Math.sqrt(varianceX + varianceY)
  }
  
  /**
   * 计算鼠标移动总距离
   */
  calculateTotalMouseDistance(moves) {
    if (moves.length < 2) return 0
    
    let totalDistance = 0
    for (let i = 1; i < moves.length; i++) {
      const dx = moves[i].x - moves[i-1].x
      const dy = moves[i].y - moves[i-1].y
      totalDistance += Math.sqrt(dx * dx + dy * dy)
    }
    
    return totalDistance
  }
  
  /**
   * 计算直线移动比例
   */
  calculateStraightLineRatio(moves) {
    if (moves.length < 3) return 0
    
    let straightMoves = 0
    for (let i = 2; i < moves.length; i++) {
      const dx1 = moves[i-1].x - moves[i-2].x
      const dy1 = moves[i-1].y - moves[i-2].y
      const dx2 = moves[i].x - moves[i-1].x
      const dy2 = moves[i].y - moves[i-1].y
      
      // 计算方向变化角度
      const angle1 = Math.atan2(dy1, dx1)
      const angle2 = Math.atan2(dy2, dx2)
      const angleDiff = Math.abs(angle1 - angle2)
      
      // 如果角度变化很小，认为是直线移动
      if (angleDiff < 0.1) {
        straightMoves++
      }
    }
    
    return straightMoves / (moves.length - 2)
  }
  
  /**
   * 计算平均点击间隔
   */
  calculateAverageClickInterval() {
    const clicks = this.behaviorData.clickTimes
    if (clicks.length < 2) return 0
    
    const intervals = []
    for (let i = 1; i < clicks.length; i++) {
      intervals.push(clicks[i].timestamp - clicks[i-1].timestamp)
    }
    
    return intervals.reduce((a, b) => a + b, 0) / intervals.length
  }
  
  /**
   * 生成会话ID
   */
  generateSessionId() {
    return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)
  }
  
  /**
   * 获取设备信息
   */
  getDeviceInfo() {
    // #ifdef H5
    if (typeof navigator !== 'undefined') {
      return {
        userAgent: navigator.userAgent,
        platform: navigator.platform,
        language: navigator.language,
        cookieEnabled: navigator.cookieEnabled,
        onLine: navigator.onLine,
        screenWidth: screen.width,
        screenHeight: screen.height,
        colorDepth: screen.colorDepth,
        timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
      }
    }
    // #endif
    
    // #ifdef MP-WEIXIN
    try {
      const systemInfo = uni.getSystemInfoSync()
      return {
        platform: systemInfo.platform,
        system: systemInfo.system,
        version: systemInfo.version,
        screenWidth: systemInfo.screenWidth,
        screenHeight: systemInfo.screenHeight,
        windowWidth: systemInfo.windowWidth,
        windowHeight: systemInfo.windowHeight
      }
    } catch (error) {
      console.error('获取设备信息失败:', error)
    }
    // #endif
    
    return {}
  }
  
  /**
   * 清理监控数据
   */
  cleanup() {
    this.stopMonitoring()
    
    // #ifdef H5
    if (typeof document !== 'undefined') {
      document.removeEventListener('mousemove', this.handleMouseMove)
      document.removeEventListener('click', this.handleClick)
      document.removeEventListener('keydown', this.handleKeydown)
      document.removeEventListener('scroll', this.handleScroll)
      window.removeEventListener('focus', this.handleFocus)
      window.removeEventListener('blur', this.handleBlur)
      document.removeEventListener('visibilitychange', this.handleVisibilityChange)
    }
    // #endif
  }
}

// 创建全局实例
const antiCheatMonitor = new AntiCheatMonitor()

export default antiCheatMonitor